﻿// **********************************************************************
//
// Author: KingSley
// Email:3268374537@qq.com
// Created:	2018/8/1   09:30
// Introduce: 对文件读写相关的整合封装
//
// **********************************************************************
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

namespace KingSley
{
    public class FileUtil
    {
        public static string LoadTextFile(string path)
        {
            string content = "";
            if (File.Exists(path))
            {
                content = File.ReadAllText(path);
            }
            return content;
        }
        public static string ReadAllText(string path)
        {
            return File.ReadAllText(path);
        }

        public static byte[] ReadAllBytes(string path)
        {
            return File.ReadAllBytes(path);
        }

        public static void CreateParentDirectory(string path)
        {
            string directoryName = Path.GetDirectoryName(path);
            if (directoryName != "" && !Directory.Exists(directoryName))
                Directory.CreateDirectory(directoryName);
        }

        public static void WriteAllText(string path, string content)
        {
            if (string.IsNullOrEmpty(path))
                return;
            try
            {
                CreateParentDirectory(path);

                File.WriteAllText(path, content);

                SetNoBackupFlag(path);
            }
            catch (System.Exception ex)
            {
                Debug.LogException(ex);
            }

        }

        public static void WriteAllBytes(string path, byte[] bytes)
        {
            if (string.IsNullOrEmpty(path))
                return;

            try
            {
                CreateParentDirectory(path);

                File.WriteAllBytes(path, bytes);

                SetNoBackupFlag(path);
            }
            catch (Exception ex)
            {
                Debug.LogException(ex);
            }
        }

        public static void SetNoBackupFlag(string path)
        {
            if (Application.platform != RuntimePlatform.IPhonePlayer)
                return;
        }

        public static void Move(string src, string dest)
        {
            if (src == dest)
                return;

            if (!File.Exists(src) && !Directory.Exists(src))
            {
                Debug.LogError("找不到源文件(夹):" + src);
                return;
            }

            CreateParentDirectory(dest);

            var attrs = File.GetAttributes(src);
            if ((attrs & FileAttributes.Directory) > 0)
            {
                if (Directory.Exists(dest))
                    Directory.Delete(dest, true);

                Directory.Move(src, dest);
            }
            else
            {

                DeleteFile(dest);

                File.Move(src, dest);

                SetNoBackupFlag(dest);
            }


        }

        public static void Copy(string src, string dest, bool overwrite)
        {
            if (src == dest)
                return;
            if (!File.Exists(src) && !Directory.Exists(src))
            {
                Debug.LogError("找不到源文件(夹):" + src);
                return;
            }
            var attrs = File.GetAttributes(src);
            if ((attrs & FileAttributes.Directory) > 0)
            {
                CopyDirectory(src, dest, overwrite);
            }
            else
            {
                CopyFile(src, dest, overwrite);
            }
        }

        public static void CopyFile(string sourceFileName, string destFileName, bool overwrite)
        {
            if (sourceFileName == destFileName)
                return;

            if (!File.Exists(sourceFileName))
            {
                Debug.LogError("!IsFileExists(" + sourceFileName + ")");
                return;
            }

            CreateParentDirectory(destFileName);

            File.Copy(sourceFileName, destFileName, overwrite);

            SetNoBackupFlag(destFileName);
        }

        public static void CopyDirectory(string srcPath, string dstPath, string[] includeFileExtensions)
        {
            CopyDirectory(srcPath, dstPath, path => includeFileExtensions != null && includeFileExtensions.Contains(Path.GetExtension(path)));
        }

        public static void CopyDirectory(string srcPath, string dstPath, bool overwrite = true, string excludeExtension = ".meta")
        {
            CopyDirectory(srcPath, dstPath, new string[] { excludeExtension }, new string[] { excludeExtension }, overwrite);
        }

        public static void CopyDirectory(string srcPath, string dstPath, string[] excludeFileExtensions, string[] excludeDirectoryExtensions, bool overwrite = true)
        {
            CopyDirectory(srcPath, dstPath, path => excludeFileExtensions == null || !excludeFileExtensions.Contains(Path.GetExtension(path)), excludeDirectoryExtensions, overwrite);
        }

        public static void CopyDirectory(string srcPath, string dstPath, string[] excludeFileExtensions, Func<string, bool> filterDirectory, bool overwrite = true)
        {
            CopyDirectory(srcPath, dstPath, path => excludeFileExtensions == null || !excludeFileExtensions.Contains(Path.GetExtension(path)), filterDirectory, overwrite);
        }

        public static void CopyDirectory(string srcPath, string dstPath, Func<string, bool> filterFile, string[] excludeDirectoryExtensions, bool overwrite = true)
        {
            CopyDirectory(srcPath, dstPath, filterFile, path => excludeDirectoryExtensions == null || !excludeDirectoryExtensions.Contains(Path.GetExtension(path)), overwrite);
        }

        public static void CopyDirectory(string srcPath, string dstPath, Func<string, bool> filterFile, Func<string, bool> filterDirectory = null, bool overwrite = true)
        {
            if (!Directory.Exists(srcPath))
            {
                Debug.LogError(srcPath + " 文件不存在！");
                return;
            }

            if (!Directory.Exists(dstPath))
                Directory.CreateDirectory(dstPath);

            IEnumerable<string> files = Directory.GetFiles(srcPath, "*", SearchOption.TopDirectoryOnly);
            if (filterFile != null)
                files = files.Where(filterFile);

            foreach (var file in files)
            {
                File.Copy(file, Path.Combine(dstPath, Path.GetFileName(file)), overwrite);
            }

            IEnumerable<string> directories = Directory.GetDirectories(srcPath, "*", SearchOption.TopDirectoryOnly);
            if (filterDirectory != null)
                directories = directories.Where(filterDirectory);

            foreach (var srcDirectory in directories)
            {
                var srcDirectoryName = Path.GetFileName(srcDirectory);
                if (srcDirectory.Contains(".svn"))
                    continue;

                var dstDirectory = Path.Combine(dstPath, srcDirectoryName);
                CopyDirectory(srcDirectory, dstDirectory, filterFile, filterDirectory, overwrite);

                if (Directory.GetFiles(dstDirectory, "*", SearchOption.TopDirectoryOnly).Length == 0 && Directory.GetDirectories(dstDirectory, "*", SearchOption.TopDirectoryOnly).Length == 0)
                    Directory.Delete(dstDirectory);
            }
        }

        public static List<string> GetFilesName(string path, string[] includeExtensions)
        {
            return GetFiles(path, file => includeExtensions != null && includeExtensions.Contains(Path.GetExtension(file))).Select((item) => Path.GetFileName(item)).ToList();
        }

        public static List<string> GetFilesNameWithoutExtension(string path, string[] includeExtensions)
        {
            return GetFiles(path, file => includeExtensions != null && includeExtensions.Contains(Path.GetExtension(file))).Select((item) => Path.GetFileNameWithoutExtension(item)).ToList();
        }

        public static List<string> GetFilesName(string path, Func<string, bool> filter = null)
        {
            return GetFiles(path, filter).Select((item) => Path.GetFileName(item)).ToList();
        }

        public static List<string> GetFilesNameWithoutExtension(string path, Func<string, bool> filter = null)
        {
            return GetFiles(path, filter).Select((item) => Path.GetFileNameWithoutExtension(item)).ToList();
        }

        public static List<string> GetFiles(string path, string[] includeExtensions)
        {
            return GetFiles(path, file => includeExtensions != null && includeExtensions.Contains(Path.GetExtension(file)));
        }

        public static List<string> GetFiles(string path, Func<string, bool> filter = null)
        {
            if (!Directory.Exists(path))
                return null;

            IEnumerable<string> files = Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly);

            if (filter != null)
                files = files.Where(filter).ToList();

            return files.ToList();
        }

        public static List<string> GetDirectoriesName(string path, Func<string, bool> filter = null)
        {
            return GetDirectories(path, filter).Select((item) => Path.GetFileName(item)).ToList();
        }

        public static List<string> GetDirectories(string path, Func<string, bool> filter = null)
        {
            if (!Directory.Exists(path))
                return null;

            IEnumerable<string> directories = Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);

            if (filter != null)
                directories = directories.Where(filter).ToList();

            return directories.ToList();
        }

        public static void DeleteFile(string path)
        {
            if (!File.Exists(path))
                return;

            File.Delete(path);
        }

        public static void DeleteDirectory(string path, bool recursive = false)
        {
            if (!Directory.Exists(path))
                return;

            Directory.Delete(path, recursive);
        }

        public static string GetFullPathWithoutExtension(string path)
        {
            return Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path);
        }

        public static int GetFileSize(string path)
        {
            if (!File.Exists(path))
                return 0;

            FileStream fs = new FileStream(path, FileMode.Open);
            long length = fs.Length;
            fs.Close();

            return (int)length;
        }

        public static byte[] GetBytes(string text)
        {
            return Encoding.UTF8.GetBytes(text);
        }

        public static string GetMD5HashFromFile(string path)
        {
            if (!File.Exists(path))
                return null;

            FileStream file = new FileStream(path, FileMode.Open);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] computeHash = md5.ComputeHash(file);

            file.Close();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < computeHash.Length; i++)
            {
                sb.Append(computeHash[i].ToString("x2"));
            }

            return sb.ToString();
        }

        public static string GetMD5Hash(string text)
        {
            return GetMD5Hash(GetBytes(text));
        }

        public static string GetMD5Hash(byte[] buffer)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] computeHash = md5.ComputeHash(buffer);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < computeHash.Length; i++)
            {
                sb.Append(computeHash[i].ToString("x2"));
            }

            return sb.ToString();
        }

        public static void CreateOrCleanDirectory(string directoryName)
        {
            if (Directory.Exists(directoryName))
            {
                var files = Directory.GetFiles(directoryName);
                foreach (var f in files)
                    File.Delete(f);
                var dirs = Directory.GetDirectories(directoryName);
                foreach (var d in dirs)
                    Directory.Delete(d, recursive: true);
            }
            else
            {
                Directory.CreateDirectory(directoryName);
            }
        }

        public static bool DeleteFileOrDirectory(string path)
        {
            if (!File.Exists(path) && !Directory.Exists(path))
                return false;
            var attr = File.GetAttributes(path);
            if ((attr & FileAttributes.Directory) > 0)
                Directory.Delete(path, true);
            else
                File.Delete(path);
            return true;
        }
    }
}